﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace _2022Learning._04.Delegate_ObserverPattern
{
    /// <summary>
    /// 使用钓鱼的例子来实现一个发布订阅
    /// </summary>
    class OberserverPattern2
    {
    }

    /// <summary>
    /// 鱼的品类枚举
    /// </summary>
    public enum FishType
    {
        鲫鱼,
        鲤鱼,
        黑鱼,
        青鱼,
        草鱼,
        鲈鱼
    }

    /// <summary>
    /// 鱼竿（被观察者）
    /// </summary>
    public class FishingRod
    {
        public event Action<FishingEventData> FishingEvent; //声明事件

        public FishingRod()
        {
            #region 注册任务已经交个事件总线，自己反射啦，被观察者不在承担相应的任务，足够简单
            //Assembly assembly = Assembly.GetExecutingAssembly();

            //foreach (var type in assembly.GetTypes())
            //{
            //    if (typeof(IEventHandler).IsAssignableFrom(type))//判断当前类型是否实现了IEventHandler接口
            //    {
            //        Type handlerInterface = type.GetInterface("IEventHandler`1");//获取该类实现的泛型接口
            //        Type eventDataType = handlerInterface.GetGenericArguments()[0]; // 获取泛型接口指定的参数类型

            //        //如果参数类型是FishingEventData，则说明事件源匹配
            //        if (eventDataType.Equals(typeof(FishingEventData)))
            //        {
            //            //创建实例
            //            var handler = Activator.CreateInstance(type) as IEventHandler<FishingEventData>;
            //            //注册事件
            //            FishingEvent += handler.HandleEvent;
            //        }
            //    }
            //}
            #endregion

        }

        public void ThrowHook(FishingMan man)
        {
            Console.WriteLine("开始下钩！");

            //用随机数模拟鱼咬钩，若随机数为偶数，则为鱼咬钩
            if (new Random().Next() % 2 == 0)
            {
                var type = (FishType)new Random().Next(0, 5);
                var fishEventData = new FishingEventData
                {
                    EventSource = this,
                    FishType = type,
                    FishingMan = man
                };
                Console.WriteLine("铃铛：叮叮叮，鱼儿咬钩了");

                var eventData = fishEventData;
                // 不在使用委托或者事件触发，直接使用总线触发
                //FishingEvent(fishEventData);
                EventBus.Default.Trigger<FishingEventData>(eventData);//直接通过事件总线触发即可
            }
        }
    }

    /// <summary>
    ///     垂钓者（观察者）
    /// </summary>
    public class FishingMan
    {
        public FishingMan(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
        public int FishCount { get; set; }

        /// <summary>
        /// 垂钓者自然要有鱼竿啊
        /// </summary>
        public FishingRod FishingRod { get; set; }

        public void Fishing()
        {
            this.FishingRod.ThrowHook(this);
        }

        ///// <summary>
        ///// 处理事件
        ///// </summary>
        ///// <param name="eventData"></param>
        //public void HandleEvent(IEventData eventData)
        //{

        //    FishCount++;
        //    if (eventData is FishingEventData)
        //    {
        //        var fishEventData = (FishingEventData)eventData;
        //        Console.WriteLine("{0}：钓到一条[{2}]，已经钓到{1}条鱼了！", Name, FishCount, fishEventData.FishType);
        //    }
        //}

        public void Update(FishType type)
        {
            FishCount++;
            Console.WriteLine("{0}：钓到一条[{2}]，已经钓到{1}条鱼了！", Name, FishCount, type);
        }
    }

    /// <summary>
    /// 定义事件源接口，所有的事件源都要实现该接口
    /// </summary>
    public interface IEventData
    {
        /// <summary>
        /// 事件发生的时间
        /// </summary>
        DateTime EventTime { get; set; }

        /// <summary>
        /// 触发事件的对象
        /// </summary>
        object EventSource { get; set; }
    }

    /// <summary>
    /// 事件源：描述事件信息，用于参数传递
    /// </summary>
    public class EventData : IEventData
    {
        /// <summary>
        /// 事件发生的时间
        /// </summary>
        public DateTime EventTime { get; set; }

        /// <summary>
        /// 触发事件的对象，被观察者
        /// </summary>
        public Object EventSource { get; set; }

        public EventData()
        {
            EventTime = DateTime.Now;
        }
    }

    /// <summary>
    /// 钓鱼事件
    /// </summary>
    public class FishingEventData : EventData
    {
        public FishType FishType { get; set; }
        /// <summary>
        /// 观察者
        /// </summary>
        public FishingMan FishingMan { get; set; }
    }

    /// <summary>
    /// 定义事件处理器公共接口，所有的事件处理器都要实现该接口
    /// </summary>
    public interface IEventHandler
    {
    }

    /// <summary>
    /// 泛型事件处理器接口
    /// </summary>
    /// <typeparam name="TEventData"></typeparam>
    public interface IEventHandler<TEventData> : IEventHandler where TEventData : IEventData
    {
        /// <summary>
        /// 事件处理器实现该方法来处理事件
        /// </summary>
        /// <param name="eventData"></param>
        void HandleEvent(TEventData eventData);
    }

    /// <summary>
    /// 钓鱼事件处理,直接处理
    /// </summary>
    public class FishingEventHandler : IEventHandler<FishingEventData>
    {
        public void HandleEvent(FishingEventData eventData)
        {
            eventData.FishingMan.FishCount++;

            Console.WriteLine("{0}：钓到一条[{2}]，已经钓到{1}条鱼了！",
                eventData.FishingMan.Name, eventData.FishingMan.FishCount, eventData.FishType);

        }
    }
}
